home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2000 February / Macworld (2000-02).dmg / Updaters / WhiteCap 3.2.2.sea / WhiteCap 3.2.2 / WhiteCap Source / WhiteCap.cpp < prev    next >
C/C++ Source or Header  |  1999-10-29  |  24KB  |  1,067 lines

  1. #include "WhiteCap.h"
  2.  
  3. #include "EgOSUtils.h"
  4.  
  5. #if EG_MAC
  6. #include <Menus.h>
  7. #include <Windows.h>
  8. #include <Palettes.h>
  9.  
  10. #if MACAMP
  11. #include "MacAMP_Visual.h"
  12. extern VPInfoBlock gPlugInfo;
  13. #endif
  14.  
  15.  
  16. #if SOUNDJAM
  17. #include "VisFramework.h"
  18. #endif
  19.  
  20.  
  21. #include "CEgFileSpec.h"
  22. #include "Sample.h"
  23. #include "CEgIOFile.h"
  24.  
  25.  
  26. #define __setupPort        GDHandle        saveDev;                                \
  27.                          GrafPtr            savePort;                                \
  28.                         ::GetGWorld( (GWorldPtr*)(&savePort), &saveDev );        \
  29.                         ::SetPort( mOSPort );                
  30.  
  31.  
  32. #define __restorePort     ::SetGWorld( (GWorldPtr)(savePort), saveDev );            
  33. #endif
  34.  
  35. #if EG_WIN
  36. #define __setupPort
  37. #define __restorePort 
  38. #include "RectUtils.h"
  39.  
  40. #include "vis.h"
  41. extern winampVisModule gWCModule;
  42.  
  43. #endif
  44.  
  45.  
  46.  
  47.  
  48. WhiteCap::WhiteCap( CEgFileSpec& inPluginsFolder, void* inRefCon ) :
  49.     mPrefs( "WhiteCap Preferences", true ),
  50.     mConfigs( cNoDuplicates_CaseInsensitive, cSortLowToHigh) {
  51.     CEgFileSpec spec;
  52.     UtilStr name, str;
  53.     
  54.     
  55.     mPrefs.Load();
  56.     if ( mPrefs.GetPref( 'Vers' ) != WHITECAP_COMPAT_VERSION ) {
  57.         mMagScale             = 1;
  58.         mTransitionLo        = 5;
  59.         mTransitionHi        = 22;
  60.         mSlideShowInterval    = 15000;        // Factory: 15 secs per config
  61.         mScrnSaverDelay        = -1 * 60000.0;    // Factory: screen saver mode disabled
  62.         mPrefs.SetPref( 'Vers', WHITECAP_COMPAT_VERSION );
  63.         mShwT_Pref            = 0x3;
  64.         mBorderlessWind        = 0;
  65.         mHandleKeys            = 1;
  66.         mCaptureMode        = 0;
  67.         }
  68.     else {
  69.         mMagScale            = mPrefs.GetPref( 'MScl' ) / 1000.0;
  70.         mTransitionLo        = mPrefs.GetPref( 'TrLo' );
  71.         mTransitionHi        = mPrefs.GetPref( 'TrHi' );
  72.         mSlideShowInterval    = mPrefs.GetPref( 'Slde' ) * 1000.0;
  73.         mScrnSaverDelay        = mPrefs.GetPref( 'SSvr' ) * 1000.0 * 60.0;
  74.         mShwT_Pref            = mPrefs.GetPref( 'ShwT' );
  75.         mBorderlessWind        = mPrefs.GetPref( 'NoBo' );
  76.         mHandleKeys            = mPrefs.GetPref( 'Kybd' );
  77.         mCaptureMode        = 0; //mPrefs.GetPref( 'Capt' );
  78.     }
  79.     
  80.     mRefCon                = inRefCon;
  81.     mInSlideShowMode    = true;
  82.     mAtFullScreen        = false;
  83.     mOSPort                = NULL;
  84.     mNumWorlds            = 0;
  85.     mFrameCount            = 0;
  86.     mFrameCountStart    =
  87.     mLastKeyPollTime    =
  88.     mLastActiveTime     =
  89.     mLastRecordTime        = EgOSUtils::CurTimeMS();
  90.     mCurConfigNum        = -1;
  91.     mNextShapeChange    = 0x7FFFFFFF;
  92.     mFramesPer10Secs    = 400;
  93.     mDoingSetPortWin    = false;
  94.     mMouseWillAwaken    = false;
  95.     mBltEntireWindow    = false;
  96.  
  97.     // Make the first slide show happen quickly
  98.     if ( mSlideShowInterval > 0 ) 
  99.         mNextShapeChange = mFrameCountStart + 10000;
  100.  
  101.     BuildConfigList( inPluginsFolder );
  102.     
  103.     #if EG_MAC
  104.     
  105.     // If ctrl and option key held down, enter capture mode...
  106.     //mCaptureMode = true;
  107.     #endif
  108.     
  109.     // Create capture data path if we're in capture mode
  110.     if ( mCaptureMode ) {
  111.         spec.AssignPathName( "WhiteCap Capture"  );
  112.         spec.SetType( cWC_CaptureType );
  113.         mDumpFile.open( &spec );
  114.         mDumpFile.PutLong( cWhiteCapID );
  115.         mDumpFile.PutLong( WHITECAP_COMPAT_VERSION );
  116.         mDumpFile.PutLong( NUM_SAMPLE_BINS );
  117.     }
  118.     
  119.     for ( int i = 0; i < NUM_SAMPLE_BINS; i++ )
  120.         mSample[ i ] = 0;
  121. }
  122.  
  123.  
  124.  
  125.  
  126. WhiteCap::~WhiteCap() {
  127.  
  128.  
  129.     SetFullScreen( false );
  130.             
  131.     // Rewrite the prefs to disk...
  132.     mPrefs.SetPref( 'Slde', mSlideShowInterval / 1000.0 );
  133.     mPrefs.SetPref( 'SSvr', mScrnSaverDelay / 60000.0 );
  134.     mPrefs.SetPref( 'TrHi', mTransitionHi );
  135.     mPrefs.SetPref( 'TrLo', mTransitionLo );
  136.     mPrefs.SetPref( 'MScl', mMagScale * 1000 );
  137.     mPrefs.SetPref( 'ShwT', mShwT_Pref );
  138.     mPrefs.SetPref( 'NoBo', mBorderlessWind );
  139.     mPrefs.SetPref( 'Kybd', mHandleKeys    );
  140.     mPrefs.SetPref( 'Capt', mCaptureMode );
  141.     
  142.     #if MACAMP || WINAMP
  143.     Rect r;
  144.     #if MACAMP
  145.     GetWinRect( r );
  146.     #else
  147.     // Very annoying:  in Win32, the call to GetWindowRect() is returning garbage in ~WhiteCap(), so just 
  148.     // forget about saving the window position for now in windows :_(
  149.     
  150.     //GetWinRect( r );
  151.     r = mWinRectHolder;  // Just use a recent rect for now
  152.     #endif
  153.     mPrefs.SetPref( 'wTop', r.top );
  154.     mPrefs.SetPref( 'wLft', r.left );
  155.     mPrefs.SetPref( 'wBot', r.bottom );
  156.     mPrefs.SetPref( 'wRgt', r.right );
  157.     #endif
  158.     
  159.     mPrefs.Store();    
  160.     
  161.     
  162.     // Delete all the existing worlds
  163.     for ( int i = 0; i < mNumWorlds; i++ )
  164.         delete mWorld[ i ];
  165. }
  166.  
  167.  
  168.  
  169.  
  170.  
  171. bool WhiteCap::PtInTitle( Point inPt ) {
  172.     int i;
  173.     
  174.     Rect r;
  175.     GetWinRect( r );
  176.     
  177.     inPt.v -= r.top;
  178.     inPt.h -= r.left;
  179.         
  180.     for ( i = 0; i < mNumWorlds; i++ ) {
  181.         if ( ::PtInRect( inPt, &mWorld[ i ] -> mTitleRect ) )
  182.             return true;
  183.     }
  184.         
  185.     return false;
  186. }
  187.  
  188.  
  189.  
  190.  
  191. void WhiteCap::SelectConfig() {
  192.     long i, sel;
  193.     Point pt;
  194.     UtilStr name;
  195.  
  196.     EgOSUtils::GetMouse( pt );
  197.             
  198.     // If we're in full screen mode, show the mouse ptr
  199.     if ( mAtFullScreen )
  200.         EgOSUtils::ShowCursor();
  201.         
  202.     #if EG_MAC
  203.     MenuHandle    menu;
  204.  
  205.     __setupPort
  206.     
  207.     // If we found a world, show a popup menu to select from the configs
  208.     menu = ::NewMenu( 123, "\p " );
  209.     
  210.     // Add the stard slideshow item
  211.     ::AppendMenu( menu, "\p " );
  212.     ::SetMenuItemText( menu, 1, "\p(Start Slide Show)" );
  213.     if ( mInSlideShowMode )
  214.         ::DisableItem( menu, 1 );
  215.  
  216.     for ( i = 1; mConfigs.FetchSpecName( i, name ); i++ ) {
  217.         ::AppendMenu( menu, "\p " );
  218.         ::SetMenuItemText( menu, i + 1, name.getPasStr() );
  219.     }
  220.     ::CheckItem( menu, mCurConfigNum + 1, true ); 
  221.     ::InsertMenu( menu, -1 );
  222.     sel = ::PopUpMenuSelect( menu, pt.v - 6, pt.h, mCurConfigNum + 1 );
  223.     ::DeleteMenu( 123 );
  224.     ::DisposeMenu( menu );
  225.  
  226.     sel = ( sel & 0xFFFF0000 ) ? (sel & 0xFFFF) : 0;
  227.     #endif
  228.     
  229.     
  230.     #if EG_WIN
  231.     long flags;
  232.     
  233.     HMENU myMenu = ::CreatePopupMenu();
  234.     
  235.     // Add item to start slideshow
  236.     flags = MF_STRING;
  237.     if ( mInSlideShowMode )
  238.         flags |= MF_GRAYED;
  239.     else
  240.         flags |= MF_ENABLED;
  241.     ::AppendMenu( myMenu, flags, 1, "(Start Slide Show)" );
  242.     
  243.     for ( i = 1; mConfigs.FetchSpecName( i, name ); i++ ) {
  244.         flags = MF_ENABLED | MF_STRING;
  245.         
  246.         // Split up the menu if it's big...
  247.         if ( i % 35 == 0 )
  248.             flags |= MF_MENUBARBREAK;
  249.         
  250.         // Check the config that's the current/displayed config
  251.         if ( mCurConfigNum == i )
  252.             flags |= MF_CHECKED;
  253.         ::AppendMenu( myMenu, flags, i + 1, name.getCStr() );
  254.     }
  255.     sel = ::TrackPopupMenuEx( myMenu, TPM_RETURNCMD, pt.h, pt.v, mOSPort, NULL );
  256.     ::DestroyMenu( myMenu );
  257.     if ( mAtFullScreen )
  258.         ::SetCapture( mOSPort );
  259.     #endif
  260.     
  261.     if ( sel > 0 ) {
  262.         if ( sel == 1 )
  263.             EnableSlideShow();
  264.         else if ( sel >= 1 ) {
  265.             LoadConfig( sel - 1, EgOSUtils::CurTimeMS() );
  266.             mInSlideShowMode = false;
  267.         }
  268.     }
  269.         
  270.         
  271.     __restorePort
  272. }
  273.  
  274.  
  275.  
  276.  
  277.  
  278. void WhiteCap::EnableSlideShow() {
  279.  
  280.     mInSlideShowMode = true;
  281.     mNextShapeChange = mLastRecordTime;
  282.     mConfigPlayList.Randomize();
  283.  
  284. }
  285.  
  286.  
  287.  
  288.  
  289. void WhiteCap::SetFullScreen( bool inFullScreen ) {
  290.         
  291.         
  292.     // If we're in capture mode, don't allow fullscreen -- it'd be pointless
  293.     if ( mCaptureMode )
  294.         inFullScreen = false;
  295.  
  296.     
  297.     #if SOUNDJAM
  298.     VisHandlerData*    handlerData = (VisHandlerData*) mRefCon;
  299.     if ( handlerData ) {
  300.         if ( mAtFullScreen != inFullScreen ) {
  301.             if ( PlayerSetFullScreen(handlerData->appCookie, handlerData->playerProc, inFullScreen) == noErr)
  302.                 mAtFullScreen = inFullScreen;
  303.         }
  304.     }
  305.     #else
  306.     
  307.     
  308.     bool            ok;    
  309.     int                dispNum;
  310.     Point            size;
  311.  
  312.     if ( inFullScreen && ! mAtFullScreen ) {
  313.         
  314.         if ( PixPort::FullscreenAvail() ) {
  315.  
  316.             __setupPort
  317.             
  318.             // Update the positon of our win 
  319.             GetWinRect( mWinRectHolder );
  320.             dispNum = PixPort::GetOwningDisplay( *((Point*) &mWinRectHolder) );
  321.             
  322.             #if MACAMP
  323.             if ( gPlugInfo.ma -> EnterFullScreen )
  324.                 gPlugInfo.ma -> EnterFullScreen( 'XXXX' /*cPluginAuthor*/, cWhiteCapID );
  325.             ::HideWindow( mOSPort );
  326.             #endif    
  327.  
  328.             #if WINAMP
  329.             ::ShowWindow( gWCModule.hwndParent, SW_HIDE | SW_MINIMIZE );
  330.             #endif
  331.  
  332.                             
  333.             // Put in pref wheather to try 32 before 16 bit color?
  334.             ok = mPort.InitFullscreen( dispNum, size, mOSPort );
  335.             
  336.             if ( ok ) {
  337.  
  338.                 
  339.                 mDispRect.left = 0;
  340.                 mDispRect.top = 0;
  341.                 mDispRect.right = size.h;
  342.                 mDispRect.bottom = size.v;
  343.                 ResizeWorlds();
  344.                 mAtFullScreen = true;
  345.                 mFullscreenStartTime = mLastRecordTime;
  346.                 
  347.                 // If we don't expire them, there'll be an ugly gap for the time it took to go fullscreen
  348.                 for ( int i = 0; i < mNumWorlds; i++ )
  349.                     mWorld[ i ] -> ExpireSamples(); 
  350.                 }    
  351.             else {
  352.                 #if MACAMP
  353.                 if ( gPlugInfo.ma -> ExitFullScreen )
  354.                     gPlugInfo.ma -> ExitFullScreen();
  355.                 ::ShowWindow( mOSPort );
  356.                 #endif
  357.                         
  358.                 #if WINAMP
  359.                 ::ShowWindow( gWCModule.hwndParent, SW_SHOWNORMAL );
  360.                 #endif
  361.             } 
  362.                         
  363.             __restorePort
  364.         } } 
  365.     else if ( ! inFullScreen && mAtFullScreen ) {
  366.  
  367.         #if MACAMP
  368.         if ( gPlugInfo.ma -> ExitFullScreen )
  369.             gPlugInfo.ma -> ExitFullScreen();
  370.         #endif
  371.         
  372.         // Restore the window
  373.         mPort.Deactivate();
  374.         
  375.         __setupPort
  376.  
  377.         SetWinPort( mOSPort, &mWinRectHolder );
  378.         
  379.         __restorePort
  380.         
  381.         mLastMousePt.h -= 55;        
  382.         mAtFullScreen = false;
  383.         
  384.         #if WINAMP
  385.         ::ShowWindow( gWCModule.hwndParent, SW_SHOWNORMAL );
  386.         #endif
  387.     }
  388.     #endif
  389.  
  390.     if ( inFullScreen ) {
  391.     
  392.         // Changing the port (and the resolution) may change the mouse cords
  393.         EgOSUtils::GetMouse( mLastMousePt );
  394.  
  395.         // Default: mouse movement will not exit fullscreen mode
  396.         mMouseWillAwaken = false;    
  397.     }
  398.     
  399.     #if EG_MAC
  400.     ::FlushEvents( 0xFFFF, 0 );
  401.     #endif
  402. }
  403.  
  404.  
  405.  
  406. void WhiteCap::GetWinRect( Rect& outRect ) {
  407.     
  408.     if ( mOSPort ) {
  409.     
  410.         #if EG_MAC
  411.         outRect = (**(((CGrafPtr) mOSPort)->portPixMap)).bounds;
  412.         outRect.left *= -1;
  413.         outRect.top  *= -1;
  414.         outRect.right = outRect.left + mOSPort -> portRect.right;
  415.         outRect.bottom = outRect.top + mOSPort -> portRect.bottom;
  416.         #elif EG_WIN
  417.         RECT wr;
  418.         ::GetWindowRect( mOSPort, &wr );
  419.  
  420.         outRect.left    = wr.left; 
  421.         outRect.top        = wr.top;
  422.         outRect.right    = wr.right; 
  423.         outRect.bottom    = wr.bottom;
  424.         #endif 
  425.         }
  426.     else 
  427.         SetRect( &outRect, 0, 0, 0, 0 );
  428. }
  429.  
  430.  
  431. void WhiteCap::RecordSample( long inCurTime ) {
  432.     
  433.     // Apply the global magnitude scale to the sample/soundbyte
  434.     for ( int i = 0; i < NUM_SAMPLE_BINS; i++ )
  435.         mSample[ i ] *= mMagScale;
  436.     
  437.     // We'll need the 'current' time in Draw()
  438.     mLastRecordTime = inCurTime;
  439.     
  440.     // Give the sample data to the window if we're not in capture mode
  441.     if ( ! mCaptureMode ) {
  442.     
  443.         // Loop thru all the panes in the window
  444.         for ( int i = 0; i < mNumWorlds; i++ ) {
  445.  
  446.             // Tell the world to take a new sound sample (if it wants)
  447.             mWorld[ i ] -> RecordSample( inCurTime, mSample );
  448.         } }
  449.     else {
  450.         mDumpFile.PutByte( CAPTURE_SAMPLE );
  451.         mDumpFile.PutLong( inCurTime );
  452.         mDumpFile.PutBlock( mSample, sizeof( float ) * NUM_SAMPLE_BINS );
  453.     }
  454. }
  455.  
  456.  
  457.  
  458.  
  459. bool WhiteCap::HandleKey( long inChar ) {
  460.     bool handled = false;
  461.     
  462.     if ( mHandleKeys ) {
  463.         if ( inChar >= ' ' && inChar <= '~' ) {
  464.             mKeyBuf.Append( (char) inChar );
  465.             handled = true; }
  466.         else if ( inChar == 128 || inChar == 8 ) {
  467.             mKeyBuf.Keep( mKeyBuf.length() - 1 );
  468.             handled = true;
  469.         }
  470.         mLastKeyTime = mLastRecordTime;
  471.     }
  472.     
  473.     return handled;
  474. }
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481. void WhiteCap::Draw() {
  482.     Rect    r;
  483.     Point    pt;
  484.     long    i, time = mLastRecordTime;
  485.     bool    kybdPress;
  486.     void*    port;
  487.  
  488.  
  489.     // Check key-entered config
  490.     if ( mKeyBuf.length() ) {
  491.     
  492.         // Process the kybd buffer only if we haven't gotten any typing in a while
  493.         if ( time > mLastKeyTime + 2500 ) {
  494.         
  495.             // See if what was types is a command to WhiteCap (vs. a config name to switch to)
  496.             if ( mKeyBuf.compareTo( "slideshow", false ) == 0 ) {
  497.                 if ( mInSlideShowMode )
  498.                     mInSlideShowMode = false;
  499.                 else
  500.                     EnableSlideShow(); }
  501.             else {
  502.                 
  503.                 // Look for a config that best matches what was typed.  Use exact match if user didn't type a lot
  504.                 if ( mKeyBuf.length() >= 4 )
  505.                     i = mConfigs.FetchBestMatch( mKeyBuf ); 
  506.                 else
  507.                     i = mConfigs.Lookup( mKeyBuf );
  508.                     
  509.                 if ( i > 0 ) {
  510.                     LoadConfig( i, mLastRecordTime );
  511.                         
  512.                     // Do a reshuffle if the user changes configs (to avoid repeated patterns)
  513.                     if ( mInSlideShowMode )
  514.                         mConfigPlayList.Randomize();
  515.                 }
  516.             }
  517.             
  518.             mKeyBuf.Wipe();
  519.         }
  520.     }
  521.  
  522.  
  523.     // Load a random waveshape every so often, and randomize things
  524.     if ( time > mNextShapeChange && mInSlideShowMode ) {
  525.     
  526.         // Load the next config in the (randomized) config list...
  527.         i = mConfigPlayList.FindIndexOf( mCurConfigNum );
  528.         
  529.         // Make a new play list if we've reached the end of the list...
  530.         if ( i >= mConfigPlayList.Count() ) {
  531.             mConfigPlayList.Randomize();
  532.             i = 0;
  533.         }
  534.         LoadConfig( mConfigPlayList.Fetch( i + 1 ), mLastRecordTime );
  535.     }
  536.     
  537.     
  538.     // Don't bother doing mouse or kybd poll if sceeen saver mode is disabled
  539.     if ( mScrnSaverDelay > 0 ) {
  540.  
  541.         kybdPress = false;
  542.  
  543.         #if EG_MAC    
  544.         long pollDelay;
  545.         
  546.         // Calc time till next kybd poll (Don't waste valuble time checking the kybd unless we've been idle a while)
  547.         if ( mAtFullScreen )
  548.             pollDelay = 600;
  549.             
  550.         // Don't bother rapildly checking the kybd until we're really close to going into screen saver mode
  551.         else if ( time > mLastActiveTime + mScrnSaverDelay - 90000 )
  552.             pollDelay = ( mLastActiveTime + mScrnSaverDelay - time ) >> 7;
  553.         else
  554.             pollDelay = 10000;
  555.             
  556.         // If it's time to poll the kybd...
  557.         if ( time > mLastKeyPollTime + pollDelay ) {
  558.             ::GetKeys( mCurKeys );
  559.             mLastKeyPollTime = time;
  560.             
  561.             // If the keys are pressed, 'move' the mouse (ie, cause the if-block a few lines from now to 'go'
  562.             if ( ( mCurKeys[0] != mPastKeys[0] ) || 
  563.                  ( mCurKeys[1] != mPastKeys[1] ) || 
  564.                  ( mCurKeys[2] != mPastKeys[2] ) || 
  565.                  ( mCurKeys[3] != mPastKeys[3] ) ) {
  566.                 kybdPress = true;
  567.                 mPastKeys[0] = mCurKeys[0];
  568.                 mPastKeys[1] = mCurKeys[1];
  569.                 mPastKeys[2] = mCurKeys[2];
  570.                 mPastKeys[3] = mCurKeys[3];
  571.             }
  572.         }
  573.         #endif
  574.         
  575.         // Check the mouse pos and record it as active if its been moved.      
  576.         EgOSUtils::GetMouse( pt );
  577.         if ( pt.h != mLastMousePt.h || pt.v != mLastMousePt.v || kybdPress ) {
  578.             mLastMousePt        = pt;
  579.             mLastActiveTime        = time;
  580.             if ( mAtFullScreen && mMouseWillAwaken )
  581.                 SetFullScreen( false ); 
  582.         }
  583.     
  584.         // If we're elligible to enter fullscreen
  585.         if ( ! mAtFullScreen && time > mLastActiveTime + mScrnSaverDelay ) {
  586.             SetFullScreen( true );
  587.             mMouseWillAwaken = true;
  588.         }
  589.     }
  590.  
  591.     
  592.     __setupPort    
  593.     
  594.     // Tell the PixPort we're about to start accessing it big time
  595.     port = mPort.BeginFrame();
  596.     if ( ! port )
  597.         port = mOSPort;
  598.  
  599.     if ( ! mCaptureMode ) {
  600.     
  601.         // Loop thru all the panes in the window and the the whitecap wave thingy
  602.         for ( i = 0; i < mNumWorlds; i++ ) {
  603.  
  604.             // Tell the world to update itself to the offscreen draw port
  605.             mWorld[ i ] -> Render( time, mPort, r );
  606.             
  607.             // If we're doing a capture playback, we have to make the dirty rect the entire pane
  608.             if ( mBltEntireWindow )
  609.                 r = *mWorld[ i ] -> PaneRect();
  610.             
  611.             // If we're drawing to a window, draw it right away
  612.             if ( mPort.IsFullscreen() )
  613.                 mPort.UnionDirtyRect( &r );
  614.             else 
  615.                 mPort.CopyBits( mOSPort, &r, &r );
  616.         }
  617.         
  618.         // See if we want to draw the title...
  619.         bool drawTitle;
  620.         if ( mAtFullScreen )
  621.             drawTitle = ( mShwT_Pref & 0x1 ) != 0;
  622.         else 
  623.             drawTitle = ( mShwT_Pref & 0x2 ) != 0;
  624.             
  625.         if ( drawTitle ) {
  626.  
  627.             // In the case we're using DrawSpocks, the cur port is the 'screen' port
  628.             #if MACAMP
  629.             if ( mPort.IsFullscreen() )
  630.                 ::GetPort( (GrafPtr*) &port );
  631.             #endif
  632.             
  633.             #if WINAMP
  634.             if ( ! mAtFullScreen )
  635.                 port = ::GetDC( mOSPort );
  636.             #endif
  637.             
  638.             // For each pane/world, draw the title string...        
  639.             for ( i = 0; i < mNumWorlds; i++ ) {
  640.                 
  641.                 mWorld[ i ] -> DrawConfigName( port );
  642.  
  643.                 // In mac land, we may need to tell the port to refresh the given rect on the screen
  644.                 #if EG_MAC        
  645.                 mPort.UnionDirtyRect( &mWorld[ i ] -> mTitleRect );
  646.                 #endif
  647.             }
  648.  
  649.             #if WINAMP
  650.             if ( ! mAtFullScreen )
  651.                 ::ReleaseDC( mOSPort, (HDC) port );
  652.             #endif
  653.         }
  654.             
  655.  
  656.         #if EG_MAC
  657.         
  658.         // If the option key is down, show the frame rate
  659.         unsigned char km[16];
  660.         ::GetKeys( (unsigned long*) km );
  661.         i = 58;    
  662.         if ( ((km[ i >> 3 ] >> (i & 7)) & 1) != 0 ) {
  663.         
  664.             // Calc frame rate, show the current computation for frames
  665.             if ( time - mFrameCountStart >= 1500 ) {
  666.                 mFramesPer10Secs = 10000 * mFrameCount / ( time - mFrameCountStart );
  667.                 mFrameRate.Assign( mFramesPer10Secs );
  668.                 mFrameRate.Insert( mFrameRate.length() - 1, ".", 1 );
  669.                 mFrameCountStart = time;
  670.                 mFrameCount = 0;
  671.             }
  672.             mFrameCount++;
  673.                 
  674.             Rect r = { 0, 0, 20, 40 };
  675.             ::EraseRect( &r );
  676.             ::MoveTo( 5, 15 );
  677.             ::DrawString( mFrameRate.getPasStr() );
  678.             if ( mPort.IsFullscreen() )
  679.                 mPort.UnionDirtyRect( &r );
  680.         }
  681.         
  682.         #endif
  683.     }
  684.     else  {
  685.         #if EG_MAC
  686.         ::MoveTo( 5, 20 );
  687.         ::DrawString( "\pCapturing..." );
  688.         #endif   
  689.     }
  690.  
  691.  
  692.     mPort.EndFrame();
  693.     
  694.     
  695.     __restorePort
  696.  
  697.  
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706. #define ___max( a, b ) (( (a) > (b) ) ? (a) : (b))
  707. #define ___maxSide( r ) (___max( r.right - r.left, r.bottom - r.top ))
  708.  
  709.  
  710. void WhiteCap::SetWinPort( GrafPtr inWin, const Rect* inRect ) {
  711.     Rect r;
  712.     
  713.     // mDoingSetPortWin == true is a signal that another thread is in SetWinPort()
  714.     if ( mDoingSetPortWin )
  715.         return;
  716.     mDoingSetPortWin = true;
  717.         
  718.     if ( inRect )
  719.         r = *inRect;
  720.     
  721.     // If an invalid win rect, fix it, you monkey!
  722.     if ( r.right - r.left < 20  || r.bottom - r.top < 20 || ! inRect ) {
  723.     
  724.         r.top                = mPrefs.GetPref( 'wTop' );
  725.         r.left                = mPrefs.GetPref( 'wLft' );
  726.         r.right                = mPrefs.GetPref( 'wRgt' );
  727.         r.bottom            = mPrefs.GetPref( 'wBot' );
  728.         
  729.         #if EG_MAC
  730.         // Invalidate the window if it's offscreen...
  731.         RgnHandle deskRgn = ::GetGrayRgn();
  732.         ::SectRect( &(*deskRgn) -> rgnBBox, &r, &r );
  733.         #endif
  734.     }
  735.  
  736.     // If no prefs avail (or an older version, use factory rect) or a bad win, hard code a size
  737.     if ( mPrefs.GetPref( 'Vers' ) != WHITECAP_COMPAT_VERSION || r.right - r.left < 20  || r.bottom - r.top < 20 ) {
  738.         r.top = 52;
  739.         r.left = 16;
  740.         r.right = 480;
  741.         r.bottom = 380; 
  742.     }
  743.  
  744.     long x = r.right - r.left;
  745.     long y = r.bottom - r.top;
  746.     
  747.     // Make width a double-word multiple
  748.     r.right -= x % 4;
  749.     
  750.             
  751.     #if EG_MAC
  752.     ::MoveWindow( inWin, r.left, r.top, true );
  753.     ::SizeWindow( inWin, x, y, true ); 
  754.     ::ShowWindow( inWin );
  755.     #else
  756.     RECT cr;
  757.     
  758.     // Resize the window and find the rgn we have to work with
  759.     ::MoveWindow( inWin, r.left, r.top, x, y, false );
  760.     ::GetClientRect( inWin, &cr );
  761.     x = cr.right - cr.left;
  762.     y = cr.bottom - cr.top;
  763.     #endif
  764.     
  765.     // The playpen for WhiteCap will be the entire window client rgn (what we'll give SetPort)
  766.     Rect portRect;
  767.     ::SetRect( &portRect, 0, 0, x, y );
  768.     SetPort( inWin, portRect, false );
  769.  
  770.     // Signal that this thread is done with SetPortWin()
  771.     mDoingSetPortWin = false;
  772. }
  773.  
  774.  
  775.  
  776.  
  777.  
  778. void WhiteCap::SetPort( GrafPtr inPort, const Rect& inRect, bool inFullScreen ) {
  779.     long x = inRect.right - inRect.left;
  780.     long y = inRect.bottom - inRect.top;
  781.  
  782.     mOSPort = inPort;
  783.     mPort.Init( x, y );
  784.     mDispRect = inRect;
  785.     mAtFullScreen = inFullScreen;
  786.     
  787.     
  788.     __setupPort
  789.     
  790.     
  791.     // If we're brand spankin new, show at least 1 config, you monkey
  792.     if ( mNumWorlds == 0 )
  793.         LoadConfig( mCurConfigNum, mLastRecordTime );
  794.     
  795.     __restorePort
  796.         
  797.     for ( int i = 0; i < mNumWorlds; i++ )
  798.         mWorld[ i ] -> ExpireSamples();
  799.         
  800.     ResizeWorlds();
  801. }
  802.  
  803.  
  804.  
  805.     
  806. void WhiteCap::ResizeWorlds() {
  807.     Rect r;
  808.     long i, j, bestLen, cutLen, best;
  809.  
  810.     
  811.     // Resize the panes in this window...
  812.     mWorld[ 0 ] -> SetPaneRect( mDispRect );
  813.     for ( i = 1; i < mNumWorlds; i++ ) {
  814.         
  815.         // Find the best world to cut in half
  816.         for ( bestLen = -1, j = 0; j < i; j++ ) {
  817.             cutLen = ___maxSide( (*mWorld[ j ] -> PaneRect()) );
  818.             if ( cutLen >= bestLen ) {
  819.                 bestLen = cutLen;
  820.                 best = j;
  821.             }
  822.         }
  823.         
  824.         // Change the pane rect of both the unplaced world and the world that's about to get cut in half
  825.         r = *(mWorld[ best ] -> PaneRect());
  826.         if ( r.right - r.left == bestLen ) {
  827.             r.right -= bestLen / 2;
  828.             mWorld[ best ] -> SetPaneRect( r );
  829.             OffsetRect( &r,  bestLen / 2,  0 );
  830.             mWorld[ i ] -> SetPaneRect( r ); }
  831.         else {
  832.             r.bottom -= bestLen / 2;
  833.             mWorld[ best ] -> SetPaneRect( r );
  834.             OffsetRect( &r,  0,  bestLen / 2 );
  835.             mWorld[ i ] -> SetPaneRect( r ); 
  836.         }                
  837.     }
  838. }
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848. void WhiteCap::RefreshRect( const Rect& inUpdate ) {
  849.  
  850.     for ( int i = 0; i < mNumWorlds; i++ ) {
  851.         mWorld[ i ] -> RefreshRect( inUpdate );        
  852.     }
  853. }
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861. void WhiteCap::LoadConfig( int inConfigNum, long inCurTime ) {
  862.     const CEgFileSpec* configSpec;
  863.     int i, exists;
  864.     long oldNumWorlds = mNumWorlds;
  865.     long transitionTime = EgOSUtils::Rnd( mTransitionLo * 1000, mTransitionHi * 1000 );
  866.         
  867.     mNumWorlds = 0;
  868.     mCurConfigNum = -1;
  869.     
  870.     // Don't bother initiating a config change if we're already running that config
  871.     if ( inConfigNum == mCurConfigNum )
  872.         return;
  873.         
  874.     // Fetch the spec for our config file or folder
  875.     configSpec = mConfigs.FetchSpec( inConfigNum );
  876.     
  877.     if ( configSpec ) {
  878.  
  879.          // If we have a folder or file...
  880.          exists = configSpec -> Exists();
  881.         if ( exists == 2 ) {
  882.             CEgFileSpec spec;
  883.             
  884.             bool startOver = true;
  885.             while ( EgOSUtils::GetNextFile( *configSpec, spec, startOver, false ) ) {
  886.                 if ( mNumWorlds >= oldNumWorlds )
  887.                     mWorld[ mNumWorlds ] = new WhiteCapWorld;
  888.                 mWorld[ mNumWorlds ] -> Init( &spec, inCurTime, transitionTime );
  889.                 mNumWorlds++;
  890.                 startOver = false;
  891.             }
  892.         }
  893.         
  894.         // Know what to put a check mark next to in the popup menu
  895.         mCurConfigNum = inConfigNum; 
  896.     }
  897.     
  898.     // If we're in capture, signal a config change...
  899.     if ( mCaptureMode ) {
  900.         UtilStr name;
  901.         if ( mConfigs.FetchSpecName( mCurConfigNum, name ) ) {
  902.             mDumpFile.PutByte( CAPTURE_CONFIG_CHANGE );
  903.             name.WriteTo( &mDumpFile );
  904.         }
  905.     }
  906.  
  907.     
  908.     // If it's only one config file or there's no spec specifed
  909.     if ( mNumWorlds == 0 ) {
  910.         mNumWorlds = 1;
  911.         if ( mNumWorlds > oldNumWorlds )
  912.             mWorld[ 0 ] = new WhiteCapWorld;
  913.         mWorld[ 0 ] -> Init( configSpec, inCurTime, transitionTime );
  914.     }
  915.     
  916.     for ( i = mNumWorlds; i < oldNumWorlds; i++ )
  917.         delete mWorld[ i ];
  918.  
  919.     // Set the time for when we load a random config automatically
  920.     mNextShapeChange = mLastRecordTime + mSlideShowInterval + transitionTime;
  921.     
  922.     // If the cursor was spun, init it back to the ptr
  923.     EgOSUtils::ResetCursor();
  924.  
  925.     // Make sure all WhiteCap's configs live happily inside the allowed draw area
  926.     ResizeWorlds();
  927.  
  928.     // Very annoying:  in Win32, the call to GetWindowRect() is returning garbage in ~WhiteCap(), so just 
  929.     // forget about saving the window position for now in windows :_(
  930.     #if EG_WIN
  931.     if ( ! mAtFullScreen )
  932.         GetWinRect( mWinRectHolder );
  933.     #endif
  934.  
  935.     if ( mAtFullScreen )
  936.         EgOSUtils::HideCursor();
  937. }
  938.  
  939.  
  940.  
  941.  
  942. void WhiteCap::BuildConfigList( CEgFileSpec& inPluginsFolder ) {
  943.     CEgFileSpec spec;
  944.     bool startOver = true;
  945.     int i;
  946.         
  947.     while ( EgOSUtils::GetNextFile( inPluginsFolder, spec, startOver, false ) ) {
  948.         mConfigs.AddCopy( spec );
  949.         startOver = false;
  950.     }
  951.     
  952.     startOver = true;
  953.     while ( EgOSUtils::GetNextFile( inPluginsFolder, spec, startOver, true ) ) {
  954.         mConfigs.AddCopy( spec );
  955.         startOver = false;
  956.     }
  957.     
  958.     // Always have a item called (Default) in the config list
  959.     UtilStr        def( "(Default)" );
  960.     spec.Assign( inPluginsFolder );
  961.     if ( ! mConfigs.Lookup( def ) ) {
  962.         spec.Rename( def );
  963.         mConfigs.AddCopy( spec );
  964.     }
  965.     mCurConfigNum = mConfigs.Lookup( def );
  966.  
  967.     // Build a random config 'play' list
  968.     mConfigPlayList.RemoveAll();
  969.     for ( i = mConfigs.Count(); i > 0; i-- ) 
  970.         mConfigPlayList.Add( i );
  971.     mConfigPlayList.Randomize();    
  972. }
  973.  
  974.  
  975.  
  976. CEgErr WhiteCap::DoDump( CEgIStream* inStream, long inNumSampleBins, long inFPS ) {
  977.     CEgFileSpec spec;
  978.     long captureCode, t, frame, minNextTime;
  979.     long frameDelay = 1000 / inFPS;
  980.     UtilStr str;
  981.     CEgIOFile oFile;
  982.     CEgErr err;
  983.     
  984.     frame = 0;
  985.     minNextTime = -1;
  986.     mHandleKeys = false;
  987.     mCaptureMode = false;
  988.     mBltEntireWindow = true;
  989.  
  990.  
  991.     spec.SetType( 'PICT' );
  992.     #if EG_MAC
  993.     PicHandle    pic;
  994.     GrafPtr        port;
  995.     
  996.     ::GetPort( &port );                
  997.     ::SetPort( mOSPort );
  998.     #endif
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.     captureCode = inStream -> GetByte();
  1005.     while ( inStream -> noErr() && err.noErr() && frame < 1050 ) {
  1006.     
  1007.         switch ( captureCode ) {
  1008.         
  1009.             case CAPTURE_SAMPLE:
  1010.             
  1011.                 // Mimic a legit sound sample being recorded
  1012.                 t = inStream -> GetLong();
  1013.                 inStream -> GetBlock( mSample, sizeof( float ) * NUM_SAMPLE_BINS );
  1014.                 if ( t < minNextTime )
  1015.                     break;
  1016.                 minNextTime += frameDelay;
  1017.                 RecordSample( t );
  1018.                 frame++;
  1019.  
  1020.                 // Generate the frame datapath
  1021.                 str.Assign( frame );
  1022.                 while ( str.length() < 4 )
  1023.                     str.Prepend( "0" );
  1024.                 str.Prepend(  "WC." );
  1025.                 spec.AssignPathName( str.getCStr() );
  1026.                 oFile.open( &spec );
  1027.                 err = oFile;
  1028.  
  1029.                 #if EG_MAC
  1030.                 
  1031.                 // Get the OS to script the frame
  1032.                 pic = ::OpenPicture( &mDispRect );
  1033.                 Draw();
  1034.                 ::ClosePicture();
  1035.                 oFile.CEgOStream::skip( 512 );
  1036.                 oFile.PutBlock( *pic, ::GetHandleSize( (Handle) pic ) );
  1037.                 oFile.close();
  1038.                 ::DrawPicture( pic, &mDispRect );
  1039.                 ::KillPicture( pic );
  1040.                 #endif
  1041.                 
  1042.                 break;
  1043.             
  1044.             case CAPTURE_CONFIG_CHANGE:
  1045.             
  1046.                 // Mimic something entered from the kybd...
  1047.                 mKeyBuf.ReadFrom( inStream );
  1048.                 mLastKeyTime = mLastRecordTime - 1000000;
  1049.                 break;
  1050.         }
  1051.         
  1052.         captureCode = inStream -> GetByte();
  1053.         EgOSUtils::SpinCursor();
  1054.     }
  1055.     
  1056.     #if EG_MAC
  1057.     ::SetPort( port );
  1058.     #endif
  1059.     
  1060.     // If any prefs were changed, don't save the changes
  1061.     mPrefs.SetNotDirty();
  1062.     
  1063.     return err;
  1064. }
  1065.  
  1066.